
import type { Config } from '#types/unicloud'
import { resolve } from 'path';
import { isExists, delDir, clearUniDir } from "#utils/fsV"
import { get_file_link, get_api_name } from "#utils/rollup_utils"
import { loadConfig } from 'unconfig';
import chokidar from 'chokidar'
import mri from 'mri'
import throttle from '#utils/throttle'
import { BuildRouter, BuildApi, copyPlugin, writeValidate } from '#utils/build'
import { devBuildApi, devBuildRouter, writeDevValidate, presetApi } from '#utils/dev'
import * as fs from 'fs';
import { pathToFileURL } from 'url'
import log from "#utils/log"
async function init() {
    // 获取文件参数
    const argv = mri(process.argv.slice(2))


    /* 获取Config */
    const { config }: { config: Config } = await loadConfig({
        sources: [{
            files: 'config',
            extensions: ['ts', 'js', 'json']
        }],
        cwd: argv.m ? resolve(process.cwd(), argv.m) : process.cwd(),
        merge: false
    });
    if (typeof config === 'undefined') {
        throw new Error("'config' file is Not defined")
    }
    const { ts = true, uniCloud_url: outInput, common, tsbufferValidator } = config
    //打包到哪里
    if (isExists(resolve(process.cwd(), outInput)) !== "dir") {
        throw new Error("The `uniClound_url` folder does not exist")
    }
    if (ts) {
        if (isExists(resolve(process.cwd(), "tsconfig.json")) !== "file") {
            //判断tsconfig.json文件是否存在
            throw new Error("'tsconfig.json' is not defined");
        }
    }

    // 框架文件名
    const file_name = ts ? 'index.ts' : 'index.js'
    // API入口
    const api_input_url = argv.m ? argv.m + "/src" : "src"
    // middleware入口
    const middleware_input_url = argv.m ? argv.m + "/middleware" : "middleware"
    // 路由入口
    const router_input_url = argv.m ? argv.m + "/router" : "router"
    // 路由入口
    const routerInputUrl = resolve(process.cwd(), router_input_url + '/' + file_name)
    if (isExists(routerInputUrl) !== "file") {
        throw new Error("The router_input_url params does not exist")
    }
    /* 存储路由入口 */
    process.env.ROUTERINPUT = routerInputUrl
    /* 存储API入口 */
    process.env.APIINPUT = api_input_url
    /* 存储中间件入口文件 */
    process.env.MIDDLEWAREINPUT = middleware_input_url
    /* 存储文件名类型 */
    process.env.FILENAME = file_name
    /* 存储开发模式 */
    process.env.ISTS = ts ? 'ts' : 'js'
    /* 存储unicloud打包路径 */
    process.env.UNICLOUDURL = outInput
    /* 存储全局系统路径 */
    process.env.SPLITSTR = process.platform === "win32" ? "\\" : "/"

    if (argv.dev) {
        clearUniDir() //重置unicloud文件夹
        const rollup_api_input_url = get_file_link(api_input_url)
        if (ts) {
            // 开启参数校验
            if (tsbufferValidator) {
                // 复制工具文件到云函数
                copyPlugin()
                // 写入json参数文件
                await writeValidate(rollup_api_input_url)
            }
        }
        // 打包至unicloud文件夹
        if (Object.keys(rollup_api_input_url).length > 0) {
            await devBuildApi(rollup_api_input_url, common)
        }
        await devBuildRouter(routerInputUrl, common)
        //启动开发模式监听
        devMode(tsbufferValidator && ts, common)
    }
    if (argv.build) {
        clearUniDir() //重置unicloud文件夹
        //打包文件
        build(config, routerInputUrl, common)
    }
}
init()
async function build(config: Config, routerInputUrl: string, common: string[] = []) {
    // 获取所有API文件
    const rollup_api_input_url = get_file_link(process.env.APIINPUT as string)
    if (Object.keys(rollup_api_input_url).length === 0) {
        throw new Error("No API file")
    }
    // 执行API打包
    await BuildApi(rollup_api_input_url, common)
    // 执行路由打包
    await BuildRouter(routerInputUrl, common)
    if (config.ts) {
        // 开启参数校验
        if (config.tsbufferValidator) {
            // 复制工具文件到云函数
            copyPlugin()
            // 写入json参数文件
            await writeValidate(rollup_api_input_url)
        }
    }
    log.success("----打包完成，请前往云函数查看----")
}




// 监听开发模式
function devMode(tsbufferValidator: boolean, common: string[]) {
    const api_input = process.env.APIINPUT as string
    const middleware_input = process.env.MIDDLEWAREINPUT as string
    const routerInputUrl = process.env.ROUTERINPUT as string
    const config_input = "config" + process.env.ISTS
    chokidar.watch([api_input, middleware_input, routerInputUrl, config_input], {
        ignoreInitial: true,  //启动时触发添加文件或文件夹事件
        atomic: 1000
    }).on('all', (event, path) => {
        throttle(async function () {
            const api_name = get_api_name(path)
            const path_url = pathToFileURL(path).pathname

            switch (event) {
                case 'addDir':
                    // API文件夹
                    if (path_url.indexOf(api_input) !== -1) {
                        const dir = path.substring(path.lastIndexOf(process.env.SPLITSTR as string) + 1)
                        if (dir[0] === '_') {
                            try {
                                const api_dir = dir.slice(1)
                                const c_path = path.split(dir)[0] + api_dir
                                delDir(path)
                                await presetApi(c_path)
                                log.info(`[shim:unicloud]${api_dir} API创建成功，已自动生成index.ts,proto.ts`)
                            } catch (error) {
                                log.err(`API创建失败, ${error as Error}`)
                            }
                        }
                    }
                    break;
                case 'add':
                    //暂无
                    break;
                case 'unlink':
                    // API文件夹
                    if (path_url.indexOf(api_input) !== -1) {
                        //删除dev对应文件
                        if (api_name) {
                            const api_dev_path = resolve(process.cwd(), `${process.env.UNICLOUDURL}/module/${api_name}.js`)
                            if (isExists(api_dev_path) === 'file') {
                                fs.unlinkSync(api_dev_path);
                            }
                        }
                    }
                    // middleware文件夹
                    if (path_url.indexOf(middleware_input) !== -1) {
                        // 重新打包路由框架
                        await devBuildRouter(routerInputUrl, common)
                    }
                    break;
                case 'unlinkDir':
                    // API文件夹
                    if (path_url.indexOf(api_input) !== -1) {
                        if (path_url.endsWith(api_input)) {
                            delDir(path)
                            return false
                        }
                        // 删除dev对应文件
                        if (api_name) {
                            const api_dev_path = resolve(process.cwd(), `${process.env.UNICLOUDURL}/module/${api_name}.js`)
                            if (isExists(api_dev_path) === 'file') {
                                fs.unlinkSync(api_dev_path);
                            }
                        }
                    }
                    // middleware文件夹
                    if (path_url.indexOf(middleware_input) !== -1) {
                        // 重新打包路由框架
                        await devBuildRouter(routerInputUrl, common)
                    }
                    break;
                case 'change':
                    // 只有修改才有触发打包
                    if (path_url.indexOf(api_input) !== -1) {
                        if (tsbufferValidator) {
                            if (path_url.endsWith("/proto.ts")) {
                                //生成校验文件
                                await writeDevValidate(path)
                            }
                        }
                        if (path_url.endsWith(process.env.FILENAME as string)) {
                            // api文件修改
                            let obj: Record<string, string> = {}
                            obj[`${api_name}`] = path
                            await devBuildApi(obj, common)
                            if (tsbufferValidator) {
                                await writeDevValidate(path.replace((process.env.FILENAME as string), 'proto.ts'))
                            }
                        }
                    }

                    if (path_url.indexOf(middleware_input) !== -1 || path_url.endsWith("router/index." + process.env.ISTS) || path_url.endsWith(config_input)) {
                        //重新打包路由
                        await devBuildRouter(routerInputUrl, common)
                    }
                    break;
            }
        })
    });
    log.start("正在监听中...");
}
